package com.mifengkong.kotlincommon.recyclerview.refreshload.refresh

import android.animation.ObjectAnimator
import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import com.mifengkong.kotlincommon.recyclerview.wrap.WrapRecyclerView

/**
 * Created by jack on 2018/6/20
 */
open class DropDownRefreshRecyclerView : WrapRecyclerView {

    // 下拉刷新的辅助类
    private var mRefreshCreator: RefreshViewCreator? = null
    // 下拉刷新头部的高度
    private var mRefreshViewHeight = 0
    // 下拉刷新的头部View
    private var mRefreshView: View? = null
    // 手指按下的Y位置
    private var mFingerDownY: Int = 0
    // 手指拖拽的阻力指数
    protected var mDragIndex = 0.35f
    // 当前是否正在拖动
    private var mCurrentDrag = false
    // 当前的状态
    private var mCurrentRefreshStatus: Int = 0

    companion object {
        // 默认状态
        const val REFRESH_STATUS_NORMAL = 1
        // 下拉刷新状态
        const val REFRESH_STATUS_PULL_DOWN_REFRESH = 2
        // 松开刷新状态
        const val REFRESH_STATUS_LOOSEN_REFRESHING = 3
        // 正在刷新状态
        const val REFRESH_STATUS_REFRESHING = 4
    }

    constructor(context: Context?) : this(context, null)
    constructor(context: Context?, attrs: AttributeSet?) : this(context, attrs, 0)
    constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle)

    fun addRefreshViewCreator(refreshCreator: RefreshViewCreator) {
        if (null == mRefreshCreator) {
            this.mRefreshCreator = refreshCreator
            addRefreshView()
        }
    }

    override fun setAdapter(adapter: Adapter<ViewHolder>) {
        super.setAdapter(adapter)
        addRefreshView()
    }

    private fun addRefreshView() {
        val adapter = adapter
        if (adapter != null) {
            // 添加头部的刷新View
            val refreshView = mRefreshCreator?.getRefreshView(context, this)
            if (refreshView != null) {
                addHeaderView(refreshView)
                this.mRefreshView = refreshView
            }
        }
    }

    override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
        when (ev?.action) {
            MotionEvent.ACTION_DOWN ->
                // 记录手指按下的位置 ,之所以写在dispatchTouchEvent那是因为如果我们处理了条目点击事件，
                // 那么就不会进入onTouchEvent里面，所以只能在这里获取
                mFingerDownY = ev.rawY.toInt()
            MotionEvent.ACTION_UP -> if (mCurrentDrag) {
                restoreRefreshView()
            }
        }
        return super.dispatchTouchEvent(ev)
    }

    /**
     * 重置当前刷新状态
     */
    private fun restoreRefreshView() {
        val currentTopMargin = (mRefreshView?.layoutParams as MarginLayoutParams).topMargin
        var finalTopMargin = -mRefreshViewHeight + 1
        if (mCurrentRefreshStatus == REFRESH_STATUS_LOOSEN_REFRESHING) {
            finalTopMargin = 0
            mCurrentRefreshStatus = REFRESH_STATUS_REFRESHING
            mRefreshCreator?.onRefreshing()
            if (mListener != null) {
                onRefreshing()
                mListener?.onRefresh()
            }
        }
        val distance = currentTopMargin - finalTopMargin
        if (distance <= 0) {
            return
        }
        // 回弹到指定位置
        val animator = ObjectAnimator.ofFloat(currentTopMargin.toFloat(), finalTopMargin.toFloat()).setDuration(distance.toLong())
        animator.addUpdateListener({ animation ->
            val topMargin = animation.animatedValue as Float
            setRefreshViewMarginTop(topMargin.toInt())
        })
        animator.start()
        mCurrentDrag = false
    }

    /**
     * 设置刷新View的marginTop
     */
    private fun setRefreshViewMarginTop(marginTop: Int) {
        var topMargin = marginTop
        mRefreshView?.let {
            val params = it.layoutParams as MarginLayoutParams
            if (topMargin < -mRefreshViewHeight + 1) {
                topMargin = -mRefreshViewHeight + 1
            }
            if (topMargin == -mRefreshViewHeight + 1) {
                mRefreshCreator?.restoreRefresh()
            }
            params.topMargin = topMargin
            it.layoutParams = params
        }
    }

    override fun onTouchEvent(e: MotionEvent?): Boolean {
        when (e?.action) {
            MotionEvent.ACTION_MOVE -> {
                // 如果是在最顶部才处理，否则不需要处理
                if (canScrollUp() || mCurrentRefreshStatus == REFRESH_STATUS_REFRESHING) {
                    // 如果没有到达最顶端，也就是说还可以向上滚动就什么都不处理
                    return super.onTouchEvent(e)
                }
                // 解决下拉刷新自动滚动问题
                if (mCurrentDrag) {
                    scrollToPosition(0)
                }
                // 获取手指触摸拖拽的距离
                val distanceY = ((e.rawY - mFingerDownY) * mDragIndex).toInt()
                // 如果是已经到达头部，并且不断的向下拉，那么不断的改变refreshView的marginTop的值
                if (distanceY > 0) {
                    val marginTop = distanceY - mRefreshViewHeight
                    setRefreshViewMarginTop(marginTop)
                    updateRefreshStatus(marginTop)
                    mCurrentDrag = true
                    return false
                }
            }
        }
        return super.onTouchEvent(e)
    }

    /**
     * 更新刷新的状态
     */
    private fun updateRefreshStatus(marginTop: Int) {
        mCurrentRefreshStatus = when {
            marginTop <= -mRefreshViewHeight -> REFRESH_STATUS_NORMAL
            marginTop < 0 -> REFRESH_STATUS_PULL_DOWN_REFRESH
            else -> REFRESH_STATUS_LOOSEN_REFRESHING
        }
        mRefreshCreator?.onDropDown(marginTop, mRefreshViewHeight, mCurrentRefreshStatus)
    }

    /**
     * @return Whether it is possible for the child view of this layout to
     * scroll up. Override this if the child view is a custom view.
     * 判断是不是滚动到了最顶部，这个是从SwipeRefreshLayout里面copy过来的源代码
     */
    private fun canScrollUp(): Boolean {
        return canScrollVertically(-1)
    }

    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
        super.onLayout(changed, l, t, r, b)
        if (changed) {
            if (mRefreshView != null && mRefreshViewHeight <= 0) {
                // 获取头部刷新View的高度
                mRefreshViewHeight = mRefreshView?.measuredHeight ?: 0
                if (mRefreshViewHeight > 0) {
                    // 隐藏头部刷新的View  marginTop  多留出1px防止无法判断是不是滚动到头部问题
                    setRefreshViewMarginTop(-mRefreshViewHeight + 1)
                }
            }
        }
    }

    fun autoRefresh() {
        if (null != mRefreshView) {
            val distance = mRefreshView?.measuredHeight?.toFloat() ?: 0.0f
            val animator = ObjectAnimator.ofFloat(0.0f, distance).setDuration(distance.toLong())
            animator.addUpdateListener({ animation ->
                val topMargin = animation.animatedValue as Float
                setRefreshViewMarginTop(topMargin.toInt())
            })
            animator.start()
        }
    }

    /**
     * 停止刷新
     */
    fun onRefreshComplete() {
        mCurrentRefreshStatus = REFRESH_STATUS_NORMAL
        restoreRefreshView()
        mRefreshCreator?.onStopRefresh()
    }

    open fun onRefreshing() {

    }

    // 处理刷新回调监听
    private var mListener: OnRefreshListener? = null

    fun setOnRefreshListener(listener: OnRefreshListener) {
        this.mListener = listener
    }

    interface OnRefreshListener {
        fun onRefresh()
    }
}